import requests
import pandas as pd
import sys
from datetime import datetime
import os
import json
import time

# 全局变量定义（集中管理配置和状态）
BASE_URL = "https://caigou.chinatelecom.com.cn"
TOKEN = ""
EXPORT_PATH = ""
DOWNLOAD_ROOT = ""
LOGGER = None
START_TIME = ""
END_TIME = ""
ORDER_CODE = ""
CONTRACT_CODE=""
PAGE_SIZE = 20  # 每页订单数量

class Logger:
    """日志工具类，同时输出到控制台和文件"""

    def __init__(self, log_file_path: str):
        log_dir = os.path.dirname(log_file_path)
        if not os.path.exists(log_dir):
            os.makedirs(log_dir, exist_ok=True)
        self.log_file = log_file_path

    def print(self, message: str) -> None:
        """打印并写入日志（带时间戳）"""
        print(message)
        with open(self.log_file, 'a', encoding='utf-8') as f:
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            f.write(f"[{timestamp}] {message}\n")

def init_global_vars(args):
    """初始化所有全局变量（集中配置）"""
    global BASE_URL, TOKEN, EXPORT_PATH, DOWNLOAD_ROOT, LOGGER,START_TIME,END_TIME,ORDER_CODE,CONTRACT_CODE

    # 基础配置
    BASE_URL = "https://caigou.chinatelecom.com.cn"
    EXPORT_PATH = args[5]  # 导出根路径
    CONTRACT_CODE = args[1]  # 合同编号（单独提取便于维护）
    DOWNLOAD_ROOT = os.path.join(EXPORT_PATH, f"招投标合同发票证明材料")
    START_TIME = args[3]
    END_TIME = args[4]
    # 初始化日志
    log_file = os.path.join(EXPORT_PATH, "export_log.txt")
    LOGGER = Logger(log_file)
    token_data = json.loads(args[0])
    # 逐层检查键是否存在
    if "localStorage" not in token_data:
        LOGGER.print("token_data 中缺少 'localStorage' 字段")
        raise KeyError("token_data 中缺少 'localStorage' 字段")

    localStorage = token_data["localStorage"]
    if not isinstance(localStorage, dict):
        LOGGER.print("'localStorage' 不是字典类型")
        raise TypeError("'localStorage' 不是字典类型")

    if "Admin-Token" not in localStorage:
        LOGGER.print("'localStorage' 中缺少 'Admin-Token' 字段")
        raise KeyError("'localStorage' 中缺少 'Admin-Token' 字段")

    TOKEN = localStorage["Admin-Token"]
    # token = token_data["localStorage"]["Admin-Token"]

    LOGGER.print(f"导出路径: {EXPORT_PATH}")
    LOGGER.print(f"合同编号: {CONTRACT_CODE}")
    LOGGER.print(f"下载根目录: {DOWNLOAD_ROOT}")
    LOGGER.print(f"开始时间: {START_TIME}")
    LOGGER.print(f"结束时间: {END_TIME}")
    LOGGER.print(f"Token: {TOKEN}")

    # 初始化Token（实际使用时建议从安全渠道获取）
    #TOKEN = "eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImQ1M2IwZjAwLWY2MGUtNDUwZS1hMDQ4LTM0Y2ViYWIxNTlhOCJ9.nweReBN7mQVb8jTckbR4oQn-PyL0LV3eF-BPV5hRcpV1skngSDjpUUUI4BbcnNC9XBSex9p-mfywNfXAJ4PwqA"

    # 初始化下载根目录
    try:
        os.makedirs(DOWNLOAD_ROOT, exist_ok=True)
        LOGGER.print(f"下载根目录: {os.path.abspath(DOWNLOAD_ROOT)}")
    except OSError as e:
        LOGGER.print(f"创建下载目录失败: {str(e)}")
        sys.exit(1)

def get_common_headers() :
    """获取通用请求头（避免重复定义）"""
    return {
        "accept": "application/json, text/plain, */*",
        "accept-language": "zh-CN,zh;q=0.9,ru;q=0.8",
        "authorization": f"Bearer {TOKEN}",
        "content-type": "application/json;charset=UTF-8",
        "origin": "https://caigou.chinatelecom.com.cn",
        "referer": "https://caigou.chinatelecom.com.cn/statisticalSetting",
        "sec-ch-ua": "\"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"138\", \"Google Chrome\";v=\"138\"",
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": "\"Windows\"",
        "sec-fetch-dest": "empty",
        "sec-fetch-mode": "cors",
        "sec-fetch-site": "same-origin",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
    }

#根据框架合同号导出结算单列表
def export_telecom_bill():
    """
    导出电信采购平台账单数据为Excel

    Args:
        各参数同原函数描述

    Returns:
        保存文件的路径，失败则返回None
    """
    # 创建输出目录
    try:
        LOGGER.print(f"导出路径: {EXPORT_PATH}")
        os.makedirs(EXPORT_PATH, exist_ok=True)
    except OSError as e:
        LOGGER.print(f"创建Excel输出目录失败: {str(e)}")
        return None

    # 构建请求参数
    payload = {
        "pageNum": 1,
        "pageSize": 10,
        "createTimeStart": START_TIME,
        "createTimeEnd": END_TIME,
        "smallContractCode": CONTRACT_CODE,
        "orderCode":"",
        "orderPackageCode":"",
        "orderPackageName":"",
        "provinceCode":"",
        "sapCode":"",
    }
    LOGGER.print(payload)
    try:
        # 发送请求
        response = requests.post(
            url="https://caigou.chinatelecom.com.cn/portal/provider/exportBill",
            headers=get_common_headers(),
            json=payload,
            stream=True,
            timeout=300
        )

        response.raise_for_status()

        # 解析文件名
        content_disposition = response.headers.get("content-disposition", "")
        if "filename=" in content_disposition:
            filename = content_disposition.split("filename=")[-1].strip('"')
        else:
            timestamp = time.strftime("%Y%m%d_%H%M%S")
            filename = f"bill_export_{timestamp}.xlsx"

        # 保存文件
        file_path = os.path.join(EXPORT_PATH, filename)
        with open(file_path, "wb") as f:
            for chunk in response.iter_content(chunk_size=8192):
                if chunk:
                    f.write(chunk)

        LOGGER.print(f"Excel文件已保存到: {file_path}")
        return file_path

    except requests.exceptions.RequestException as e:
        LOGGER.print(f"导出Excel请求异常: {str(e)}")
        return None
    except Exception as e:
        LOGGER.print(f"保存Excel文件失败: {str(e)}")
        return None

def supple_settlement_statement(excel_path):
    '''
    在结算单导出的excel中增加商务需求的字段
    用订单号调 查询收获列账的接口 返回框架号、框架合同名称、数量
    再用订单号调 查询我的订单的接口 返回订单名称、备货订单号、采购类型、费用类型、采购申请单位、采购管理员、价款、税款
    '''
    try:
        df = pd.read_excel(excel_path)
        # 保留结算单需求字段
        required_columns = ['省份','公司主体','法律订单编码', '结算单编号','订单编码']
        # df = df[required_columns]
        # df.to_excel(excel_path,index=False)
        for col in required_columns:
            if col not in df.columns:
                LOGGER.print(f"错误：结算单Excel缺少必要字段 - {col}")
                return None
        # 定义要添加的新列
        new_columns = [
            '框架号',
            '框架合同名称',
            '收获列账数量',
            '订单名称',
            '备货订单号',
            '采购类型',
            '费用类型',
            '采购申请单位',
            '采购管理员',
            '价款',
            '税款'
        ]
        # 初始化新列
        for col in new_columns:
            df[col] = None
        for index,row in df.iterrows():
            order_num = row['订单编码']
            if pd.isna(order_num):
                continue
            # 用订单编号查询收获列账 和 我的订单
            goods_receipt_info = query_goods_receipt_post(order_num)
            my_order_info = query_my_order(order_num)
            if len(goods_receipt_info) > 0 and len(my_order_info) > 0:
                # excel增加字段
                df.at[index,'框架号'] = goods_receipt_info[0]
                df.at[index,'框架合同名称'] = goods_receipt_info[1]
                df.at[index, '收获列账数量'] = goods_receipt_info[2]
                df.at[index,'订单名称'] = my_order_info[0]
                df.at[index,'备货订单号'] = my_order_info[1]
                procurement_type = ''  # 采购类型
                if str(my_order_info[2]) == '04':
                    procurement_type = '集二'
                elif str(my_order_info[2]) == '10':
                    procurement_type = '省一'
                else:
                    procurement_type = str(my_order_info[2])
                df.at[index, '采购类型'] = procurement_type
                expense_type = ''  # 费用类型
                if str(my_order_info[3]) == '101':
                    expense_type = '设备费'
                else:
                    expense_type = str(my_order_info[3])
                df.at[index, '费用类型'] = expense_type
                df.at[index,'采购申请单位'] = my_order_info[4]
                df.at[index,'采购管理员'] = my_order_info[5]
                df.at[index,'价款'] = my_order_info[6]
                df.at[index,'税款'] = my_order_info[7]
            else:
                LOGGER.print(f'{'收获列账表查询错误' if len(goods_receipt_info) == 0  else '我的订单查询错误'} - {order_num}')
            # 添加延迟避免请求过于频繁
            time.sleep(0.2)
        df.to_excel(excel_path, index=False)
        LOGGER.print(f"收货列账和我的订单字段补充完成，已保存到 {excel_path}")
    except Exception as e:
        LOGGER.print(f"在Excel文件中增加字段失败: {str(e)}")
        return None

def query_goods_receipt_post(order_num):
    '''查收获列账返回需求字段'''
    try:
        url = 'https://caigou.chinatelecom.com.cn/portal/orderReport/list'
        payload = {
            "applyCompanyName": None,
            "applyTypeCode": None,
            "frameContName": None,
            "isProxyOrder": None,
            "managerName": None,
            "managerPhone": None,
            "modelCode": None,
            "modelName": None,
            "orderCode": order_num,  # 订单编号
            "originalName": None,
            "pageNum": 1,
            "pageSize": 10,
            "provinceCode": None,
            "purchaseApplyCompanyName": None,
            "receiveStatus": None,
            "sapCode": None,
            "serviceTypeCode": None,
            "smallContractCode": None,
            "stockOrderCode": None,
        }
        response = requests.post(url, json=payload, headers=get_common_headers())
        response.raise_for_status()
        result = response.json()

        if result.get('code') != 200:
            LOGGER.print(f"查询该订单收货列账信息失败: {result.get('msg')}")
            return []
        # 获取该订单的合同号(框架号)、框架合同名称、数量（收货列账数量）
        data = result['data']['pageInfo']['list']
        if len(data) > 0:
            contractCode = data[0]['contractCode']  # 合同号
            frameContName = data[0]['frameContName']  # 框架合同名称
            num = data[0]['num']
            return [contractCode,frameContName,num]
        else:
            LOGGER.print(f"该订单未查询到收货列账信息: {result.get('msg')}")
            return []

    except requests.exceptions.RequestException as e:
        LOGGER.print(f"查询收货列账请求异常: {str(e)}")
    except Exception as e:
        LOGGER.print(f"查询收货列账失败: {str(e)}")

def query_my_order(order_num):
    '''传入订单编码，返回需求字段'''
    try:
        url = 'https://caigou.chinatelecom.com.cn/portal/purchaseOrder/listMyOrder'
        today = datetime.now().date().strftime('%Y-%m-%d')
        payload = {
            "applyTypeCodes": None,
            "collectState": "",
            "contractName": "",
            "createTimeEnd": "",
            "createTimeStart": today,  # 当天日期 2025-08-27
            "creatorName": "",
            "delivery": "",
            "frameContName": "",
            "isProxyOrder": "",
            "isSelfTake": "",
            "isSlhgl": "",
            "orderCode": order_num,
            "orderName": "",
            "orderOriginQuery": "",
            "pageNum": 1,
            "pageSize": 10,
            "providerDealStatus": "",
            "providerNameOfwl": "",
            "provinceCode": "",
            "purchaseApplyCompanyName": "",
            "purchaseTypeCode": "",
            "receiveStatus": "",
            "sapCode": "",
            "serviceTypeCode": "",
            "smallContractCode": "",
            "stockOrderCode": "",
            "subId": 2
        }
        response = requests.post(url, json=payload, headers=get_common_headers())
        response.raise_for_status()
        result = response.json()

        if result.get('code') != 200:
            LOGGER.print(f"查询我的订单信息失败: {result.get('msg')}")
            return []
        # 获取该订单的订单名称、备货订单号、采购类型、费用类型、采购申请单位、采购管理员
        data = result['data']['pageInfo']['list']
        if len(data) > 0:
            orderName = data[0]['orderName'] # 订单名称
            stockOrderCode = data[0]['stockOrderCode'] # 备货订单号
            provinceCode = data[0]['provinceCode'] # 采购类型 找了三个字段只有这个能和采购类型保持一致 可能省份和采购类型是绑定的  04---江苏  集二    10---广西  省一
            serviceTypeCode = data[0]['serviceTypeCode'] # 费用类型 101-设备费
            purchaseApplyCompanyName = data[0]['purchaseApplyCompanyName'] # 采购申请单位
            creatorName = data[0]['creatorName'] # 采购管理员
            amount = data[0]['amount'] # 价款
            taxAmount = data[0]['taxAmount'] # 税款
            return [orderName,stockOrderCode,provinceCode,serviceTypeCode,purchaseApplyCompanyName,creatorName,amount,taxAmount]
        else:
            LOGGER.print(f"该订单未查询到我的订单信息: {result.get('msg')}")
            return []


    except requests.exceptions.RequestException as e:
        LOGGER.print(f"查询我的订单请求异常: {str(e)}")
    except Exception as e:
        LOGGER.print(f"查询我的订单失败: {str(e)}")


def main():
    # 获取命令行参数
    args = sys.argv[1:]
    if len(args) < 7:
        LOGGER.print(
            "参数错误！使用方式: python script.py [token] [框架合同编号] [商品名称] [开始时间] [结束时间] [导出路径] [目录结构标识]")
        sys.exit(1)
    """主函数：初始化并执行流程"""
    init_global_vars(args)

    # 导出excel并处理
    LOGGER.print("开始导出Excel数据...")
    excel_path = export_telecom_bill()
    if excel_path:
        # 在结算单表增加收货列账和我的订单的部分字段
        supple_settlement_statement(excel_path)
        # LOGGER.print("开始处理Excel数据并下载文件...")
        # export_excel(excel_path)
    else:
        LOGGER.print("Excel导出失败，终止流程")

if __name__=='__main__':
    main()